'use client';

import { ChevronDownIcon } from 'lucide-react';
import type { ComponentProps, ReactNode } from 'react';
import { createContext, useContext, useState } from 'react';
import { Button } from '../../components/button';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../../components/collapsible';
import { Input } from '../../components/input';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../components/tooltip';
import { cn } from '../../utils/index';

export type WebPreviewContextValue = {
    url: string;
    setUrl: (url: string) => void;
    consoleOpen: boolean;
    setConsoleOpen: (open: boolean) => void;
};

const WebPreviewContext = createContext<WebPreviewContextValue | null>(null);

const useWebPreview = () => {
    const context = useContext(WebPreviewContext);
    if (!context) {
        throw new Error('WebPreview components must be used within a WebPreview');
    }
    return context;
};

export type WebPreviewProps = ComponentProps<'div'> & {
    defaultUrl?: string;
    onUrlChange?: (url: string) => void;
};

export const WebPreview = ({
    className,
    children,
    defaultUrl = '',
    onUrlChange,
    ...props
}: WebPreviewProps) => {
    const [url, setUrl] = useState(defaultUrl);
    const [consoleOpen, setConsoleOpen] = useState(false);

    const handleUrlChange = (newUrl: string) => {
        setUrl(newUrl);
        onUrlChange?.(newUrl);
    };

    const contextValue: WebPreviewContextValue = {
        url,
        setUrl: handleUrlChange,
        consoleOpen,
        setConsoleOpen,
    };

    return (
        <WebPreviewContext.Provider value={contextValue}>
            <div
                className={cn('flex size-full flex-col rounded-lg border bg-card', className)}
                {...props}
            >
                {children}
            </div>
        </WebPreviewContext.Provider>
    );
};

export type WebPreviewNavigationProps = ComponentProps<'div'>;

export const WebPreviewNavigation = ({
    className,
    children,
    ...props
}: WebPreviewNavigationProps) => (
    <div className={cn('flex items-center gap-1 border-b p-2', className)} {...props}>
        {children}
    </div>
);

export type WebPreviewNavigationButtonProps = ComponentProps<typeof Button> & {
    tooltip?: string;
};

export const WebPreviewNavigationButton = ({
    onClick,
    disabled,
    tooltip,
    children,
    ...props
}: WebPreviewNavigationButtonProps) => (
    <TooltipProvider>
        <Tooltip>
            <TooltipTrigger asChild>
                <Button
                    className="h-8 w-8 p-0 hover:text-foreground"
                    disabled={disabled}
                    onClick={onClick}
                    size="sm"
                    variant="ghost"
                    {...props}
                >
                    {children}
                </Button>
            </TooltipTrigger>
            <TooltipContent>
                <p>{tooltip}</p>
            </TooltipContent>
        </Tooltip>
    </TooltipProvider>
);

export type WebPreviewUrlProps = ComponentProps<typeof Input>;

export const WebPreviewUrl = ({ value, onChange, onKeyDown, ...props }: WebPreviewUrlProps) => {
    const { url, setUrl } = useWebPreview();

    const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
        if (event.key === 'Enter') {
            const target = event.target as HTMLInputElement;
            setUrl(target.value);
        }
        onKeyDown?.(event);
    };

    return (
        <Input
            className="h-8 flex-1 text-sm"
            onChange={onChange}
            onKeyDown={handleKeyDown}
            placeholder="Enter URL..."
            value={value ?? url}
            {...props}
        />
    );
};

export type WebPreviewBodyProps = ComponentProps<'iframe'> & {
    loading?: ReactNode;
};

export const WebPreviewBody = ({ className, loading, src, ...props }: WebPreviewBodyProps) => {
    const { url } = useWebPreview();

    return (
        <div className="flex-1">
            <iframe
                className={cn('size-full', className)}
                sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-presentation"
                src={(src ?? url) || undefined}
                title="Preview"
                {...props}
            />
            {loading}
        </div>
    );
};

export type WebPreviewConsoleProps = ComponentProps<'div'> & {
    logs?: Array<{
        level: 'log' | 'warn' | 'error';
        message: string;
        timestamp: Date;
    }>;
};

export const WebPreviewConsole = ({
    className,
    logs = [],
    children,
    ...props
}: WebPreviewConsoleProps) => {
    const { consoleOpen, setConsoleOpen } = useWebPreview();

    return (
        <Collapsible
            className={cn('border-t bg-muted/50 font-mono text-sm', className)}
            onOpenChange={setConsoleOpen}
            open={consoleOpen}
            {...props}
        >
            <CollapsibleTrigger asChild>
                <Button
                    className="flex w-full items-center justify-between p-4 text-left font-medium hover:bg-muted/50"
                    variant="ghost"
                >
                    Console
                    <ChevronDownIcon
                        className={cn(
                            'h-4 w-4 transition-transform duration-200',
                            consoleOpen && 'rotate-180',
                        )}
                    />
                </Button>
            </CollapsibleTrigger>
            <CollapsibleContent
                className={cn(
                    'px-4 pb-4',
                    'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 outline-none data-[state=closed]:animate-out data-[state=open]:animate-in',
                )}
            >
                <div className="max-h-48 space-y-1 overflow-y-auto">
                    {logs.length === 0 ? (
                        <p className="text-muted-foreground">No console output</p>
                    ) : (
                        logs.map((log, index) => (
                            <div
                                className={cn(
                                    'text-xs',
                                    log.level === 'error' && 'text-destructive',
                                    log.level === 'warn' && 'text-yellow-600',
                                    log.level === 'log' && 'text-foreground',
                                )}
                                key={`${log.timestamp.getTime()}-${index}`}
                            >
                                <span className="text-muted-foreground">
                                    {log.timestamp.toLocaleTimeString()}
                                </span>{' '}
                                {log.message}
                            </div>
                        ))
                    )}
                    {children}
                </div>
            </CollapsibleContent>
        </Collapsible>
    );
};
